/*
 * @Author: Wangjun
 * @Date: 2023-09-01 13:39:49
 * @LastEditTime: 2025-10-05 13:29:06
 * @LastEditors: wangjun haodreams@163.com
 * @Description:创建默认的router
 * @FilePath: \golib\autoroute\defaulter\default.go
 * hnxr
 */
package easyroute

import (
	"strings"

	"gitee.com/haodreams/golib/autoroute/controller"
	"gitee.com/haodreams/golib/minauth"
	"gitee.com/haodreams/golib/startruntime"
	"gitee.com/haodreams/libs/config"
	"gitee.com/haodreams/libs/easy"
	"github.com/gin-contrib/gzip"
	"github.com/gin-contrib/pprof"
	"github.com/gin-gonic/gin"
)

// 默认的认证
func DefaultAuth(c *gin.Context) (any, error) {
	//如果是本地发起的请求则不需要认证s
	host := c.RemoteIP()
	if host == "127.0.0.1" { //本地不做验证
		return nil, nil
	}
	return minauth.CallbackNeedAuth(c)
}

// 创建默认的路由
// 开启缓存，不能通过安全认证
func NewEngine(cached bool) (router *gin.Engine) {
	router = gin.New()
	gin.SetMode(config.DefaultString("gin.mode", gin.ReleaseMode))

	Init(router, cached)
	return router
}

func BasicSetup(router *gin.Engine, cached bool, auth func(*gin.Context) (any, error)) {
	if !cached { //安全扫描出现的响应头缺失安全问题
		router.Use(SecureHeader)
	}
	router.Use(gin.Recovery())                                                                   //开启故障恢复
	router.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedPathsRegexs([]string{".*"}))) //开启压缩
	router.StaticFile("/favicon.ico", "static/favicon.ico")

	if config.DefaultBool("pprof.enable", false) {
		pprof.Register(router)
	}
	router.GET("/sys/status", func(c *gin.Context) { //获取服务器当前时间
		c.String(200, easy.Now())
	})
}

func Init(router *gin.Engine, cached bool) {
	if !cached { //安全扫描出现的响应头缺失安全问题
		router.Use(SecureHeader)
	}
	router.Use(gin.Recovery())                                                                   //开启故障恢复
	router.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedPathsRegexs([]string{".*"}))) //开启压缩

	if config.DefaultBool("pprof.enable", false) {
		pprof.Register(router)
	}

	ris := router.Routes()
	mapRoute := make(map[string]bool)
	for _, route := range ris {
		mapRoute[route.Path] = true
	}

	if ok := mapRoute["/"]; !ok {
		router.StaticFile("/", "static/dist/index.html")
	}
	if ok := mapRoute["/static"]; !ok {
		router.Static("/static", "static")
	}

	router.StaticFile("/favicon.ico", "static/favicon.ico")

	router.GET("/sys/starttime", func(c *gin.Context) { //获取运行时间
		c.String(200, easy.FormatTime(startruntime.GetStartRunTime()))
	})

	router.GET("/sys/status", func(c *gin.Context) { //获取服务器当前时间
		c.String(200, easy.Now())
	})
	router.GET("/sys/encrypt", getEncrypt)   //获取加密字符串页面
	router.POST("/sys/encrypt", postEncrypt) //加密字符串

	//注册md路由
	//Register("/sys/log", (&page.TailLogController{}), router)
	// funcGetSession func(*gin.Context) (sess.Sessioner, error)
	// Register("/md", WithSession(new(page.MdController), funcGetSession), router)
	// Register("/sys/file", WithSession(new(page.FileController), funcGetSession), router)
}

/**
 * @description: 安全认证扫描
 * @param {*gin.Context} ctx
 * @return {*}
 */
func SecureHeader(ctx *gin.Context) {
	// 解决安全漏洞：检测到目标服务器启用了OPTIONS方法
	header := ctx.Writer.Header()
	header.Set("Access-Control-Allow-Origin", "*")
	// Access-Control-Allow-Credentials跨域问题
	header.Set("Access-Control-Allow-Credentials", "true")
	header.Set("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE")
	header.Set("Access-Control-Max-Age", "86400")
	header.Set("Access-Control-Allow-Headers", "*")

	// 点击劫持：X-Frame-Options未配置
	header.Add("X-Frame-Options", "SAMEORIGIN")
	// 检测到目标Referrer-Policy响应头缺失
	header.Add("Referer-Policy", "origin")
	// 检测到目标Referrer-Policy响应头缺失
	header.Add("Referrer-Policy", "origin")
	// Content-Security-Policy响应头确实
	header.Add("Content-Security-Policy", "object-src 'self'")
	// 检测到目标X-Permitted-Cross-Domain-Policies响应头缺失
	header.Add("X-Permitted-Cross-Domain-Policies", "master-only")
	// 检测到目标X-Content-Type-Options响应头缺失
	header.Add("X-Content-Type-Options", "nosniff")
	// 检测到目标X-XSS-Protection响应头缺失
	header.Add("X-XSS-Protection", "1; mode=block")
	// 检测到目标X-Download-Options响应头缺失
	header.Add("X-Download-Options", "noopen")
	// 点击劫持：X-Frame-Options未配置
	header.Add("X-Frame-Options", "SAMEORIGIN")
	// HTTP Strict-Transport-Security缺失
	header.Add("Strict-Transport-Security", "max-age=63072000; includeSubdomains; preload")
	ctx.Next()
}

func UseCache(ctx *gin.Context) {
	path := ctx.Request.URL.Path
	if strings.HasSuffix(path, ".png") || strings.HasSuffix(path, ".js") || strings.HasSuffix(path, ".css") {
		ctx.Writer.Header().Set("Cache-Control", "public, max-age=86400")
	}
	ctx.Next()
}

/**
 * @description: 开启默认的认证
 * @param {*} cb 扩展的认证方式
 * @return {*}
 */
func UseDefaultAuth(defaultUser func() (user, passwd string), cb ...func(*gin.Context) (any, error)) {
	if len(cb) > 0 && cb != nil {
		controller.SetNeedAuthCallback(cb[0])
	} else {
		controller.SetNeedAuthCallback(minauth.CallbackNeedAuth)
	}
	initUser(defaultUser)
}

// 初始化用户
func initUser(defaultUser func() (user, passwd string)) {
	minauth.Init(defaultUser)
}

// 加密字符串
func getEncrypt(c *gin.Context) {
	html := `<!DOCTYPE html>
		<html> <head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<title>数据加密</title>
		</head><body><form method="post">
		数据加密:<input type="input" name="key" value="" /> 	<input type="submit" name="submit" />
		</form> </body></html>
		`
	c.Writer.Header().Add("Content-Type", "text/html")
	c.Writer.WriteHeader(200)
	c.Writer.Write([]byte(html))
}

func postEncrypt(c *gin.Context) {
	c.Request.ParseForm()
	keys := c.Request.PostForm["key"]
	if len(keys) > 0 {
		keys[0] = strings.TrimSpace(keys[0])
		if keys[0] != "" {
			c.String(200, config.EncodeValue(keys[0]))
		}
		return
	}
	c.String(200, "参数错误")
}
